package org.acghub.mtdb.util;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

public class Parser implements LineParser {
    public static String IMPORT_BEGIN = "// {{{ XMLGEN_IMPORT_BEGIN";
    public static String IMPORT_END = "// XMLGEN_IMPORT_END }}}";
    public static String DEFINE_BEGIN = "// {{{ XMLGEN_DEFINE_BEGIN";
    public static String DEFINE_END = "// XMLGEN_DEFINE_END }}}";

    private final List<String> lines = new ArrayList<String>();
    private int importBeginLine = -1;
    private int defineBeginLine = -1;
    private State state = State.Others;

    public void verify(String info) {
        if (importBeginLine < 0 || defineBeginLine < 0 || importBeginLine > defineBeginLine || importBeginLine > lines.size() || defineBeginLine > lines.size()) {
            throw new RuntimeException(info + " is not a xmlgen file");
        }
    }

    public void printBeforeImport(PrintStream ps) {
        for (int i = 0; i < importBeginLine; ++i)
            ps.println(lines.get(i));
    }

    public void printImportToDefine(PrintStream ps) {
        for (int i = importBeginLine; i < defineBeginLine; ++i)
            ps.println(lines.get(i));
    }

    public void printAfterDefine(PrintStream ps) {
        for (int i = defineBeginLine; i < lines.size(); ++i)
            ps.println(lines.get(i));
    }

    @Override
    public void parseLine(String line) {
        // State old = state;
        switch (state) {
            case ImportBegin:
                skipUntil(line, State.ImportEnd);
                break;

            case DefineBegin:
                skipUntil(line, State.DefineEnd);
                break;

            case Others:
                State c = lineState(line);
                switch (c) {
                    case ImportBegin -> {
                        if (importBeginLine >= 0) throw new RuntimeException("too many import section");
                        importBeginLine = lines.size();
                        state = State.ImportBegin;
                    }
                    case DefineBegin -> {
                        if (defineBeginLine >= 0) throw new RuntimeException("too many define section");
                        defineBeginLine = lines.size();
                        state = State.DefineBegin;
                    }
                    case Others -> lines.add(line);
                    default -> throw new IllegalStateException(state + "->" + c);
                }
            default:
                break;
        }
    }

    private State lineState(String line) {
        if (line.contains(IMPORT_BEGIN)) return State.ImportBegin;
        if (line.contains(IMPORT_END)) return State.ImportEnd;
        if (line.contains(DEFINE_BEGIN)) return State.DefineBegin;
        if (line.contains(DEFINE_END)) return State.DefineEnd;
        return State.Others;
    }

    private void skipUntil(String line, State target) {
        State c = lineState(line);
        if (c == target) state = State.Others;
        else if (State.Others == c) {
        } else throw new IllegalStateException(state + "->" + c);
    }

    enum State {
        ImportBegin, ImportEnd, DefineBegin, DefineEnd, Others
    }
}
